package com.tceasy.gateway.util;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;

import javax.net.ssl.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyStore;

public class HttpClient {
	private static final Logger logger=LoggerFactory.getLogger(HttpClient.class);
	
	public static String sendRequestByGet(String url,String param){
        String urlAndParam=new StringBuilder(url).append(StringUtils.isBlank(param)?"":"?"+param).toString();
		return sendRequestByGet(urlAndParam, true);
	}

    public static String sendRequestByGet(String url,boolean isPrintLog){
        return sendRequestByGet(url,MediaType.APPLICATION_FORM_URLENCODED_VALUE,isPrintLog);
    }

    /**
     * get请求
     * @param url
     * @param isPrintLog
     * @param contentType
     * @return
     */
    public static String sendRequestByGet(String url,String contentType, boolean isPrintLog) {
        return sendRequestByGet(url,contentType,isPrintLog,"utf-8");
    }

    /**
	 * get请求
	 * @param url
	 * @param isPrintLog
	 * @return
	 */
	public static String sendRequestByGet(String url, String contentType, boolean isPrintLog,String encode) {
		String result = "";
		BufferedReader in = null;
		HttpURLConnection connection = null;
        if(StringUtils.isBlank(encode)){
            encode="utf-8";
        }
		try {
			if (isPrintLog) {
				logger.info("get请求参数url:" + url);
			}
			URL paostUrl = new URL(url);
			//请求配置
			connection = (HttpURLConnection) paostUrl.openConnection();
			connection.setRequestProperty("Content-Type",contentType);
			connection.setRequestMethod("GET");
			connection.setDoOutput(true);
			connection.setDoInput(true);
			connection.setUseCaches(false);
			connection.setInstanceFollowRedirects(true);
			connection.setConnectTimeout(30000);
			connection.setReadTimeout(30000);
			
            in = new BufferedReader(new InputStreamReader(connection.getInputStream(),encode));
            String line = in.readLine();  
            while (line != null) {  
            	result += line;  
                line = in.readLine();  
            }  
		} catch (Exception e) {
			logger.error("get请求发生异常"+",url="+url, e);
		} finally {
			try {
				if (in != null) {
					in.close();
				}
				if (connection != null) {
					connection.disconnect();
					connection = null;
				}
			} catch (IOException e) {
				logger.error("error", e);
			}
		}
        logger.info("请求结果：{}",result);
		return result;
	}

    /**
	 * post请求 form表单方式
	 * @param url
	 * @param paramStr
	 * @return
	 */
	public static String sendRequestByPost(String url, String paramStr, boolean isPrintLog) {
	    return sendRequestByPostGiveContentType(url, paramStr, isPrintLog, MediaType.APPLICATION_FORM_URLENCODED_VALUE,null);
	}

    /**
     * post请求 form表单方式
     * @param url
     * @param paramStr
     * @return
     */
    public static String sendRequestByPost(String url, String paramStr, boolean isPrintLog,String encode) {
        return sendRequestByPostGiveContentType(url, paramStr, isPrintLog, MediaType.APPLICATION_FORM_URLENCODED_VALUE,encode);
    }

    /**
     * post请求josn方式
     * @param url
     * @param paramStr
     * @return
     */
    public static String sendRequestByPostJson(String url, String paramStr,boolean isPrintLog) {
        return sendRequestByPostGiveContentType(url, paramStr, isPrintLog, MediaType.APPLICATION_JSON_VALUE,null);
    }

    /**
     * post请求 form表单方式且有auth
     * @param url
     * @param paramStr
     * @return
     */
    public static String sendRequestByPost(String url, String paramStr, boolean isPrintLog,String userName,String pwd) {
        return sendRequestByPostGiveContentType(url, paramStr, isPrintLog, MediaType.APPLICATION_FORM_URLENCODED_VALUE,userName,pwd);
    }
	
	/**
	 * post请求 Content-Type json
	 * @param url
	 * @param paramStr
	 * @param isPrintLog
	 * @return
	 */
	public static String sendRequestByPostTextXml(String url, String paramStr,boolean isPrintLog) {
        return sendRequestByPostGiveContentType(url, paramStr, isPrintLog, MediaType.TEXT_XML_VALUE,null);
    }

    /**
     * post请求 Content-Type json
     * @param url
     * @param paramStr
     * @param isPrintLog
     * @return
     */
    public static String sendRequestByPostAndXml(String url, String paramStr,String encode, boolean isPrintLog) {
        return sendRequestByPostGiveContentType(url, paramStr, isPrintLog, MediaType.APPLICATION_XML_VALUE,encode);
    }

	
	public static String sendRequestByPostGiveContentType(String url, String paramStr, boolean isPrintLog, String contentType,String encode,String ...authorization){

        String result = "";
        BufferedReader in = null;
        HttpURLConnection connection = null;
        OutputStream out = null;
        if(StringUtils.isBlank(encode)){
            encode="utf-8";
        }
        try {
            if (isPrintLog) {
                logger.info("post请求参数url:" + url + ",paramStr:" + paramStr);
            }
            URL paostUrl = new URL(url);
            //参数配置
            connection = (HttpURLConnection) paostUrl.openConnection();
            connection.setRequestProperty("Content-Type", contentType);
            connection.setRequestMethod("POST");
            connection.setDoOutput(true); //http正文内，因此需要设为true, 默认情况下是false
            connection.setDoInput(true); //设置是否从httpUrlConnection读入，默认情况下是true
            connection.setUseCaches(false); //Post 请求不能使用缓存
            connection.setInstanceFollowRedirects(true); //URLConnection.setInstanceFollowRedirects是成员函数，仅作用于当前函数
            connection.setConnectTimeout(30000); //设置连接主机超时时间
            connection.setReadTimeout(30000); //设置从主机读取数据超时
            if(authorization!=null&&authorization.length>0){
                //设置auth
                String authString = authorization[0] + ":" + authorization[1];
                String auth = "Basic " + Base64.encode(authString.getBytes(encode));
                connection.setRequestProperty("Authorization", auth);
            }

            //打开连接
            out = connection.getOutputStream();
            out.write(paramStr.getBytes(encode));
            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), encode));
            String line = in.readLine();  
            while (line != null) {  
                result += line;  
                line = in.readLine();  
            }  
        } catch (Exception e) {
            logger.error("post请求发生异常"+",url="+url+",paramStr:"+paramStr, e);
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
                if (connection != null) {
                    connection.disconnect();
                }
            } catch (IOException e) {
                logger.error("error", e);
            }
        }
        logger.info("请求结果：{}",result);
        return result;
    
	}

    public static String callHttpsByPost(String url,String param,String jksPath,String jksPass){
        return callHttpsByPostGiveContentType(url,param,jksPath,jksPass,null,null);
    }

    public static String callHttpsByPost(String url,String param,String jksPath,String jksPass,String authorization){
        return callHttpsByPostGiveContentType(url,param,jksPath,jksPass,null,authorization);
    }

    /**
     * 向指定URL发送POST方法的请求,附带pkcs12证书
     * @param url    请求地址
     * @param param  请求参数
     * @param jksPath jks格式证书库路径
     * @param jksPass jks证书库密码
     * @param contentType contentType 可以为空
     * @param authorization basic Auth(格式："username:password")，可为空
     * @return
     */
    public static String callHttpsByPostGiveContentType(String url,String param,String jksPath,String jksPass,String contentType,String authorization)
    {
        HttpsURLConnection conn = null;
        OutputStream out = null;
        String result = null;
        try {
            logger.info("https请求，请求地址：{}，请求参数：{}，证书路径：{}，证书密码：{}，basicAuth:{}",new Object[]{url,param,jksPath,jksPass,authorization});
            //访问Java密钥库，JKS是keytool创建的Java密钥库，保存密钥。
            KeyStore ks = KeyStore.getInstance("JKS");
            File jksFile=new File(jksPath);
            ks.load(new FileInputStream(jksFile),jksPass.toCharArray());

            //创建用于管理JKS密钥库的密钥管理器
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            //初始化证书
            kmf.init(ks,jksPass.toCharArray());

            //同位体验证信任决策源//同位体验证可信任的证书来源
            TrustManager[] tm = { new MyX509TrustManager() };

            //初始化安全套接字
            SSLContext sslContext = SSLContext.getInstance("SSL");
            //初始化SSL环境。第二个参数是告诉JSSE使用的可信任证书的来源，设置为null是从javax.net.ssl.trustStore中获得证书。
            //第三个参数是JSSE生成的随机数，这个参数将影响系统的安全性，设置为null是个好选择，可以保证JSSE的安全性。
            sslContext.init(kmf.getKeyManagers(),tm, null);
            //根据上面配置的SSL上下文来产生SSLSocketFactory,与通常的产生方法不同
            SSLSocketFactory factory = sslContext.getSocketFactory();
            URL realUrl = new URL(url);
            //打开和URL之间的连接
            conn = (HttpsURLConnection)realUrl.openConnection();
            //创建安全的连接套接字
            conn.setSSLSocketFactory(factory);

            if(StringUtils.isNotBlank(contentType)){
                conn.setRequestProperty("Content-Type", contentType);
            }
            //发送POST请求必须设置如下两行,使用 URL 连接进行输出、入
            conn.setDoOutput(true);
            conn.setDoInput(true);
            //设置从主机读取数据超时
            conn.setReadTimeout(30000);
            //设置basic Auth
            if(StringUtils.isNotBlank(authorization)){
                String auth = "Basic " + Base64.encode(authorization.getBytes());
                conn.setRequestProperty("Authorization", auth);
            }
            // 获取URLConnection对象对应的输出流
            out = conn.getOutputStream();
            //发送请求参数
            out.write(param.getBytes());
            //flush 输出流的缓冲
            out.flush();

            //得到服务端返回
            InputStream is = conn.getInputStream();
            if(is!=null && !"".equals(is))
            {
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                byte[] receiveBuffer = new byte[2048];//缓冲区长度
                int readBytesSize = is.read(receiveBuffer);//读取数据长度，InputStream要读取的数据长度一定要小于等于缓冲区中的字节数
                System.out.println("#######readBytesSize："+readBytesSize);

                while(readBytesSize != -1){//判断流是否位于文件末尾而没有可用的字节
                    bos.write(receiveBuffer, 0, readBytesSize);//从receiveBuffer内存处的0偏移开始写，写与readBytesSize长度相等的字节
                    readBytesSize = is.read(receiveBuffer);
                    System.out.println("#######bos："+bos);
                }
                result = new String(bos.toByteArray(), "UTF-8");//编码后的tr2报文
            }
            logger.info("请求结果：{}",result);
        } catch(Exception e) {
            logger.error("发送POST请求出现异常！" , e);
        }finally {
            //使用finally块来关闭输出流、输入流
            if (out != null){
                try {
                    out.close();
                } catch (IOException e) {
                    logger.error(e.toString());
                }
            }
            if (conn != null) {
                conn.disconnect();
            }
        }
        return result;
    }
}